home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume8 / se / part01 next >
Encoding:
Internet Message Format  |  1987-01-25  |  54.2 KB

  1. Subject:  v08i001:  Georgia Tech 'se' Screen Editor
  2. Newsgroups: mod.sources
  3. Approved: mirror!rs
  4.  
  5. Submitted by: emoryu1!arnold (Arnold D. Robbins)
  6. Mod.sources: Volume 8, Issue 1
  7. Archive-name: se/Part01
  8.  
  9.  
  10. Here is the second release of the Georgia Tech Screen Editor, 'se'.
  11. There were enough changes that a whole new posting is warranted.
  12.  
  13. Major Changes:
  14.     All Georgia Tech specific stuff removed.
  15.     It understands window size changes on 4.3BSD and ATT Unix PC/3B1
  16.     Support for the shared library on the ATT Unix PC/3B1
  17.     Considerable source code reorganization in certain files.
  18.  
  19. Enjoy,
  20.  
  21. Arnold Robbins
  22.  
  23. #! /bin/sh
  24. # This is a shell archive, meaning:
  25. # 1. Remove everything above the #! /bin/sh line.
  26. # 2. Save the resulting text in a file.
  27. # 3. Execute the file with /bin/sh (not csh) to create the files:
  28. #    README
  29. #    ascii.h
  30. #    constdefs.h
  31. #    docmd1.c
  32. #    docmd2.c
  33. export PATH; PATH=/bin:$PATH
  34. echo shar: extracting "'README'" '(6131 characters)'
  35. if test -f 'README'
  36. then
  37.     echo shar: will not over-write existing file "'README'"
  38. else
  39. cat << \SHAR_EOF > 'README'
  40. # $Header: README,v 1.3 86/07/17 17:52:23 arnold Exp $
  41. # $Log:    README,v $
  42. # Revision 1.3  86/07/17  17:52:23  arnold
  43. # Fixed some spelling mistakes.
  44. # Revision 1.2  86/07/17  17:19:06  arnold
  45. # Removed GT specific stuff, added discussion of window sensitivities.
  46. # Revision 1.1  86/05/06  13:34:09  osadr
  47. # Initial revision
  48. README:
  49.  
  50. This directory contains the source files for the Unix version of the Georgia
  51. Tech Screen Editor "Se".  It has three subdirectories which contain things
  52. that se needs. Here is a rundown of the various files.
  53.  
  54. Files containing documentation are:
  55.  
  56. README        -- this file.
  57. se.m4        -- nroff manual page for se (has to be munged to create se.1).
  58. scriptse.1    -- nroff manual page for scriptse.
  59.  
  60. The header files are:
  61.  
  62. ascii.h        -- definition of ASCII mnemonics and control characters.
  63. extern.h    -- external data definitions for the screen editor.
  64. se.h        -- global #define's for the screen editor.
  65. constdefs.h    -- global constants, also used by files in subdirectories.
  66.  
  67. The C source files are:
  68.  
  69. main.c        -- main program and declaration of globals, initialization.
  70. edit.c        -- main command loop to get and execute commands, file handling.
  71. docmd1.c    -- command decoder and functions for most commands.
  72. docmd2.c    -- functions for the rest of the commands.
  73. misc.c        -- miscellanious functions.
  74. scratch.c    -- scratch file manipulating functions.
  75. screen.c    -- routines to keep track of the screen contents.
  76. term.c        -- routines for changing the terminal.
  77.  
  78. The subdirectories are:
  79.  
  80. libchangetty    -- routines to change the terminal driver back and forth.
  81. pat        -- pattern matching routines.
  82. se_h        -- contains help scripts for all commands in se.
  83.  
  84. Miscellanious files:
  85.  
  86. where        -- shell file to determine System V (R 1 or 2), 4.1, or 4.2 BSD.
  87. m4munge        -- manipulate output of where for m4 for se man page
  88. makefile    -- the makefile for make(1).
  89. print2        -- inode used by make for printing only changed stuff.
  90.  
  91. scriptse.c    -- quick and dirty C program to make scripts for se.
  92. scriptse.1    -- manual page for same.
  93.  
  94. Executable files:
  95.  
  96. se        -- executable version of the screen editor.
  97. scriptse    -- the executable version of the script maker.
  98.  
  99.  
  100. Conditional Compilation flags:
  101.  
  102.     The flag HARD_TERMS, if added to the CFLAGS macro in the makefile,
  103. will remove the terminal-independent code which uses termlib, and put back
  104. the original, terminal-types-hardwired-into-the-program code.  The only
  105. reason to do this is if se has to run on a system without the termlib package.
  106. Using termlib, se is considerably smaller, as well as more flexible.
  107.  
  108.     The flag OLD_SCRATCH, if added to the CFLAGS macro in the makefile,
  109. will cause se to use the original, linked-list method for keeping track of
  110. lines in the buffer.  This method is faster for rearranging lines, but
  111. considerably slower for simply looking up lines.  Currently, se uses the
  112. method given in Software Tools in Pascal, which keeps the lines in order in
  113. an array.  It is slower at rearranging, but as fast as possible for finding
  114. lines in the buffer.  This version also takes less data and code space.
  115.  
  116.     The flag OLD_GLOB, if added to the CFLAGS macro in the makefile,
  117. will keep se from special casing commands whose effect is to reverse the
  118. order of the lines in the buffer.  The special casing code can save an
  119. *incredible* amount of time for this pathological case, so it is best to leave
  120. things alone.  This only applies to the Software Tools in Pascal style
  121. line handling.
  122.  
  123.     The flag LOG_USAGE, if added to the CFLAGS macro in the makefile,
  124. will cause se to write usage "statistics" to a log file, consisting of the
  125. login name and time and date when an individual used se. The logfile path
  126. name in the log() routine in edit.c should be changed to use a system
  127. accounting file somewhere.  It currently creates a file in /usr/tmp.
  128.  
  129.     The 'where' command creates a file called 'flags', which the makefile
  130. cats inside ``s.  These define and/or undefine the flags USG for System V,
  131. S5R2 if for Release 2, BSD for 4.1 and 4.2, and BSD4_2 for 4.2 specific code.
  132.  
  133. Miscellanious:
  134.  
  135.     Code which is dependent on the Berkeley job control stuff is also
  136. conditionally compiled in, so that on systems without it, it won't get in
  137. the way.
  138.  
  139.     Code has been added which should allow se to come up under USG Unix
  140. 5.0 (System V).  If S5R2 is defined, se will use the terminfo package.
  141. Otherwise, it assumes Release 1, and that the BSD termlib package has
  142. been ported and is available.
  143.  
  144.     There is code in term.c to test if se is running on a system with
  145. windows or not. It currently understands the windows on an ATT Unix PC (or 3B1)
  146. and the windowing ioctl's in BRL Unix, which should be identical to those
  147. in 4.3 BSD.
  148.  
  149. Comments:
  150.  
  151.     It is a big piece of software. But, if you 1) read both Software Tools
  152. and Software Tools in Pascal (the chapters on editing and pattern matching, if
  153. you don't want to read all of the books), and 2) take your time, you should be
  154. able to understand, and eventually make changes to it, as necessary.
  155.  
  156. Authors:
  157.  
  158.     Se started out as the version of 'ed' that came with the book 'Software
  159. Tools', by Kernighan and Plauger, which was written in Ratfor. On the Pr1me
  160. computers at the School of Information and Computer Science at Georgia Tech,
  161. Dan Forsyth, Perry Flinn, and Alan Akin added all the enhancements suggested
  162. in the exercises in the book, and some more of their own. Jack Waugh made
  163. extensive modifications to turn it into a screen editor; further work was done
  164. by Dan Forsyth. All of this was in an improved Georgia Tech version of Ratfor.
  165.  
  166.     Later, Dan Forsyth, then (and now) at Medical Systems Development
  167. Corporation, converted the Ratfor version into C, for Berkeley Unix (4.1 BSD).
  168. At Georgia Tech, Arnold Robbins took the C version and added many new features
  169. and improvements, the most important of which was termcap support and System V
  170. support. The existing help screens were edited and completed at that time, as
  171. well. This was completed in early 1985.
  172.  
  173.     Arnold Robbins is now at ...!gatech!emory!arnold, and will make every
  174. reasonable attempt to answer any questions anyone may have about it, but in
  175. no way promises to support or enhance 'se'.
  176. SHAR_EOF
  177. fi # end of overwriting check
  178. echo shar: extracting "'ascii.h'" '(1389 characters)'
  179. if test -f 'ascii.h'
  180. then
  181.     echo shar: will not over-write existing file "'ascii.h'"
  182. else
  183. cat << \SHAR_EOF > 'ascii.h'
  184. /*
  185.  * $Header: ascii.h,v 1.1 86/05/06 13:35:19 osadr Exp $
  186.  */
  187.  
  188. /*
  189.  * $Log:    ascii.h,v $
  190.  * Revision 1.1  86/05/06  13:35:19  osadr
  191.  * Initial revision
  192.  * 
  193.  * 
  194.  */
  195.  
  196. /*
  197. ** ascii.h
  198. **
  199. ** definitions of ASCII mnemonics and synonyms.
  200. */
  201.  
  202. #ifndef    _ASCII_H
  203. #define    _ASCII_H
  204. #define    NUL    '\0'
  205. #define    SOH    '\001'
  206. #define    STX    '\002'
  207. #define    ETX    '\003'
  208. #define    EOT    '\004'
  209. #define    ENQ    '\005'
  210. #define    ACK    '\006'
  211. #define    BEL    '\007'
  212. #define    BS    '\010'
  213. #define    HT    '\011'
  214. #define    LF    '\012'
  215. #define    VT    '\013'
  216. #define    FF    '\014'
  217. #define    CR    '\015'
  218. #define    SO    '\016'
  219. #define    SI    '\017'
  220. #define    DLE    '\020'
  221. #define    DC1    '\021'
  222. #define    DC2    '\022'
  223. #define    DC3    '\023'
  224. #define    DC4    '\024'
  225. #define    NAK    '\025'
  226. #define    SYN    '\026'
  227. #define    ETB    '\027'
  228. #define    CAN    '\030'
  229. #define    EM    '\031'
  230. #define    SUB    '\032'
  231. #define    ESC    '\033'
  232. #define    FS    '\034'
  233. #define    GS    '\035'
  234. #define    RS    '\036'
  235. #define    US    '\037'
  236. #define    SP    '\040'
  237. #define    DEL    '\177'
  238. #define    CTRL_A    SOH
  239. #define    CTRL_B    STX
  240. #define    CTRL_C    ETX
  241. #define    CTRL_D    EOT
  242. #define    CTRL_E    ENQ
  243. #define    CTRL_F    ACK
  244. #define    CTRL_G    BEL
  245. #define    CTRL_H    BS
  246. #define    CTRL_I    HT
  247. #define    CTRL_J    LF
  248. #define    CTRL_K    VT
  249. #define    CTRL_L    FF
  250. #define    CTRL_M    CR
  251. #define    CTRL_N    SO
  252. #define    CTRL_O    SI
  253. #define    CTRL_P    DLE
  254. #define    CTRL_Q    DC1
  255. #define    CTRL_R    DC2
  256. #define    CTRL_S    DC3
  257. #define    CTRL_T    DC4
  258. #define    CTRL_U    NAK
  259. #define    CTRL_V    SYN
  260. #define    CTRL_W    ETB
  261. #define    CTRL_X    CAN
  262. #define    CTRL_Y    EM
  263. #define    CTRL_Z    SUB
  264. #endif
  265. SHAR_EOF
  266. fi # end of overwriting check
  267. echo shar: extracting "'constdefs.h'" '(325 characters)'
  268. if test -f 'constdefs.h'
  269. then
  270.     echo shar: will not over-write existing file "'constdefs.h'"
  271. else
  272. cat << \SHAR_EOF > 'constdefs.h'
  273. /*
  274.  * $Header: constdefs.h,v 1.1 86/05/06 13:35:37 osadr Exp $
  275.  */
  276.  
  277. /*
  278.  * $Log:    constdefs.h,v $
  279.  * Revision 1.1  86/05/06  13:35:37  osadr
  280.  * Initial revision
  281.  * 
  282.  * 
  283.  */
  284.  
  285. /*
  286. ** constdefs.h
  287. **
  288. ** Standard macro definitions for se screen editor
  289. */
  290.  
  291. #define    EOS '\0'
  292. #define    ERR (-3)
  293. #define    OK (-2)
  294. #define    NO 0
  295. #define    YES 1
  296. SHAR_EOF
  297. fi # end of overwriting check
  298. echo shar: extracting "'docmd1.c'" '(27523 characters)'
  299. if test -f 'docmd1.c'
  300. then
  301.     echo shar: will not over-write existing file "'docmd1.c'"
  302. else
  303. cat << \SHAR_EOF > 'docmd1.c'
  304. #ifndef lint
  305. static char RCSid[] = "$Header: docmd1.c,v 1.3 86/07/17 17:19:37 arnold Exp $";
  306. #endif
  307.  
  308. /*
  309.  * $Log:    docmd1.c,v $
  310.  * Revision 1.3  86/07/17  17:19:37  arnold
  311.  * Some general code cleaning up.
  312.  * 
  313.  * Revision 1.2  86/07/11  15:10:20  osadr
  314.  * Removed Georgia Tech specific items.
  315.  * 
  316.  * Revision 1.1  86/05/06  13:36:44  osadr
  317.  * Initial revision
  318.  * 
  319.  * 
  320.  */
  321.  
  322. /*
  323. ** docmd1.c
  324. **
  325. ** main command processor.  routines for individual commands
  326. */
  327.  
  328. #include "se.h"
  329. #include "extern.h"
  330.  
  331. /* static data definitions -- variables only needed in this file */
  332. static char Tlpat[MAXPAT] = "";    /* saved character list for y/t command */
  333. static char Tabstr[MAXLINE] = "";    /* string representation of tab stops */
  334. static char Ddir = FORWARD;        /* delete direction */
  335. static int Compress;            /* compress/expand tabs on read/write */
  336.  
  337. /* docmd --- handle all commands except globals */
  338.  
  339. int docmd (lin, i, glob, status)
  340. char lin[];
  341. int i, glob, *status;
  342. {
  343.     char file[MAXLINE], sub[MAXPAT];
  344.     char kname;
  345.     int gflag, line3, pflag, flag, fflag, junk, allbut, tflag;
  346.     int append (), ckchar (), ckp (), ckupd (), copy ();
  347.     int delete (), domark (), doopt (), doprnt (), doread ();
  348.     int doshell ();
  349.     int dotlit (), doundo (), dowrit (), getfn (), getkn ();
  350.     int getone (), getrange (), getrhs (), getstr (), inject ();
  351.     int join (), makset (), move (), nextln (), optpat ();
  352.     int prevln (), substr (), draw_box ();
  353.     char *expand_env ();
  354.  
  355.  
  356.     *status = ERR;
  357.     if (intrpt ())  /* catch a pending interrupt */
  358.         return (*status);
  359.  
  360.     switch (lin[i]) {
  361.     case APPENDCOM:
  362.     case UCAPPENDCOM:
  363.         if (lin[i + 1] == '\n' || lin[i + 1] == ':')
  364.         {
  365.             defalt (Curln, Curln);
  366.             if (lin[i + 1] == '\n')
  367.             {
  368.                 /* avoid updating with inline insertion */
  369.                 adjust_window (Line1, Line2);
  370.                 updscreen ();
  371.             }
  372.             *status = append (Line2, &lin[i + 1]);
  373.         }
  374.         break;
  375.  
  376.     case PRINTCUR:
  377.         if (lin[i + 1] == '\n')
  378.         {
  379.             defalt (Curln, Curln);
  380.             saynum (Line2);
  381.             *status = OK;
  382.         }
  383.         break;
  384.  
  385.     case OVERLAYCOM:
  386.     case UCOVERLAYCOM:
  387.         defalt (Curln, Curln);
  388.         if (lin[i + 1] == '\n')
  389.             overlay (status);
  390.         break;
  391.  
  392.     case CHANGE:
  393.     case UCCHANGE:
  394.         defalt (Curln, Curln);
  395.         if (Line1 <= 0)
  396.             Errcode = EORANGE;
  397.         else if (lin[i + 1] == '\n' || lin[i + 1] == ':')
  398.         {
  399.             if (lin[i + 1] == '\n')
  400.             {
  401.                 /* avoid updating with inline insertion */
  402.                 adjust_window (Line2, Line2);
  403.                 updscreen ();
  404.             }
  405.             First_affected = min (First_affected, Line1);
  406.             if (lin[i + 1] == '\n')
  407.                 warn_deleted (Line1, Line2);
  408.             *status = append (Line2, &lin[i + 1]);
  409.             if (*status != ERR)
  410.             {
  411.                 line3 = Curln;
  412.                 delete (Line1, Line2, status);
  413.                 Curln = line3 - (Line2 - Line1 + 1);
  414.                 /* adjust for deleted lines */
  415.             }
  416.         }
  417.         break;
  418.  
  419.     case DELCOM:
  420.     case UCDELCOM:
  421.         if (ckp (lin, i + 1, &pflag, status) == OK)
  422.         {
  423.             defalt (Curln, Curln);
  424.             if (delete (Line1, Line2, status) == OK
  425.                 && Ddir == FORWARD
  426.                 && nextln (Curln) != 0)
  427.                 Curln = nextln (Curln);
  428.         }
  429.         break;
  430.  
  431.     case INSERT:
  432.     case UCINSERT:
  433.         defalt (Curln, Curln);
  434.         if (Line1 <= 0)
  435.             Errcode = EORANGE;
  436.         else if (lin[i + 1] == '\n' || lin[i + 1] == ':')
  437.         {
  438.             if (lin[i + 1] == '\n')
  439.             {
  440.                 /* avoid updating with inline insertion */
  441.                 adjust_window (Line1, Line2);
  442.                 updscreen ();
  443.             }
  444.             *status = append (prevln (Line2), &lin[i + 1]);
  445.         }
  446.         break;
  447.  
  448.     case MOVECOM:
  449.     case UCMOVECOM:
  450.         i++;
  451.         if (getone (lin, &i, &line3, status) == EOF)
  452.             *status = ERR;
  453.         if (*status == OK && ckp (lin, i, &pflag, status) == OK)
  454.         {
  455.             defalt (Curln, Curln);
  456.             *status = move (line3);
  457.         }
  458.         break;
  459.  
  460.     case COPYCOM:
  461.     case UCCOPYCOM:
  462.         i++;
  463.         if (getone (lin, &i, &line3, status) == EOF)
  464.             *status = ERR;
  465.         if (*status == OK && ckp (lin, i, &pflag, status) == OK)
  466.         {
  467.             defalt (Curln, Curln);
  468.             *status = copy (line3);
  469.         }
  470.         break;
  471.  
  472.     case SUBSTITUTE:
  473.     case UCSUBSTITUTE:
  474.         i++;
  475.         if (lin[i] == '\n')
  476.         {
  477.             /* turn "s\n" into "s//%/\n" */
  478.             lin[i+0] = '/';
  479.             lin[i+1] = '/';
  480.             lin[i+2] = '%';
  481.             lin[i+3] = '/';
  482.             lin[i+4] = '\n';
  483.             lin[i+5] = EOS;
  484.             Peekc = SKIP_RIGHT;
  485.         }
  486.         else
  487.         {
  488.             /* try to handle "s/stuff\n" */
  489.             int j, missing_delim;
  490.  
  491.             missing_delim = YES;
  492.             for (j = i + 1; lin[j] != '\n'; j++)
  493.                 if (lin[j] == ESCAPE && lin[j+1] == lin[i])
  494.                     j++;    /* skip esc, loop continues */
  495.                 else if (lin[j] == lin[i])
  496.                 {
  497.                     missing_delim = NO;
  498.                     break;    /* for */
  499.                 }
  500.  
  501.             if (missing_delim)
  502.             {
  503.                 for (; lin[j] != EOS; j++)
  504.                     ;
  505.                 j--;        /* j now at newline */
  506.  
  507.                 lin[j] = lin[i];    /* delim */
  508.                 lin[++j] = '\n';
  509.                 lin[++j] = EOS;
  510.                 Peekc = SKIP_RIGHT;
  511.                 /* rest of routines will continue to fix up */
  512.             }
  513.         }
  514.  
  515.         if (optpat (lin, &i) == OK
  516.             && getrhs (lin, &i, sub, &gflag) == OK
  517.             && ckp (lin, i + 1, &pflag, status) == OK)
  518.         {
  519.             defalt (Curln, Curln);
  520.             *status = subst (sub, gflag, glob);
  521.         }
  522.         break;
  523.  
  524.     case TLITCOM:
  525.     case UCTLITCOM:
  526.         i++;
  527.         if (lin[i] == '\n')
  528.         {
  529.             /* turn "y\n" into "y//%/\n" */
  530.             lin[i+0] = '/';
  531.             lin[i+1] = '/';
  532.             lin[i+2] = '%';
  533.             lin[i+3] = '/';
  534.             lin[i+4] = '\n';
  535.             lin[i+5] = EOS;
  536.             Peekc = SKIP_RIGHT;
  537.         }
  538.         else
  539.         {
  540.             /* try to handle "y/stuff\n" */
  541.             int j, missing_delim;
  542.  
  543.             missing_delim = YES;
  544.             for (j = i + 1; lin[j] != '\n'; j++)
  545.                 if (lin[j] == ESCAPE && lin[j+1] == lin[i])
  546.                     j++;    /* skip esc, loop continues */
  547.                 else if (lin[j] == lin[i])
  548.                 {
  549.                     missing_delim = NO;
  550.                     break;    /* for */
  551.                 }
  552.  
  553.             if (missing_delim)
  554.             {
  555.                 for (; lin[j] != EOS; j++)
  556.                     ;
  557.                 j--;        /* j now at newline */
  558.  
  559.                 lin[j] = lin[i];    /* delim */
  560.                 lin[++j] = '\n';
  561.                 lin[++j] = EOS;
  562.                 Peekc = SKIP_RIGHT;
  563.                 /* rest of routines will continue to fix up */
  564.             }
  565.         }
  566.  
  567.         if (getrange (lin, &i, Tlpat, MAXPAT, &allbut) == OK
  568.             && makset (lin, &i, sub, MAXPAT) == OK
  569.             && ckp (lin, i + 1, &pflag, status) == OK)
  570.         {
  571.             defalt (Curln, Curln);
  572.             *status = dotlit (sub, allbut);
  573.         }
  574.         break;
  575.  
  576.     case JOINCOM:
  577.     case UCJOINCOM:
  578.         i++;
  579.         if (getstr (lin, &i, sub, MAXPAT) == OK
  580.             && ckp (lin, i + 1, &pflag, status) == OK)
  581.         {
  582.             defalt (prevln (Curln), Curln);
  583.             *status = join (sub);
  584.         }
  585.         break;
  586.  
  587.     case UNDOCOM:
  588.     case UCUNDOCOM:
  589.         i++;
  590.         defalt (Curln, Curln);
  591.         if (ckchar (UCDELCOM, DELCOM, lin, &i, &flag, status) == OK
  592.             && ckp (lin, i, &pflag, status) == OK)
  593.             *status = doundo (flag, status);
  594.         break;
  595.  
  596.     case ENTER:
  597.     case UCENTER:
  598.         i++;
  599.         if (Nlines != 0)
  600.             Errcode = EBADLNR;
  601.         else if (ckupd (lin, &i, ENTER, status) == OK
  602.             && ckchar ('x', 'X', lin, &i, &tflag, status) == OK)
  603.             if (getfn (lin, i - 1, file) == OK)
  604.             {
  605.                 strcpy (Savfil, expand_env (file));
  606.                 mesg (Savfil, FILE_MSG);
  607.                 clrbuf ();
  608.                 mkbuf ();
  609.                 dfltsopt (file);
  610.                 *status = doread (0, file, tflag);
  611.                 First_affected = 0;
  612.                 Curln = min (1, Lastln);
  613.                 Buffer_changed = NO;
  614.             }
  615.             else
  616.                 *status = ERR;
  617.         break;
  618.  
  619.     case PRINTFIL:
  620.     case UCPRINTFIL:
  621.         if (Nlines != 0)
  622.             Errcode = EBADLNR;
  623.         else if (getfn (lin, i, file) == OK)
  624.         {
  625.             strcpy (Savfil, expand_env (file));
  626.             mesg (Savfil, FILE_MSG);
  627.             *status = OK;
  628.         }
  629.         break;
  630.  
  631.     case READCOM:
  632.     case UCREADCOM:
  633.         i++;
  634.         if (ckchar ('x', 'X', lin, &i, &tflag, status) == OK)
  635.             if (getfn (lin, i - 1, file) == OK)
  636.             {
  637.                 defalt (Curln, Curln);
  638.                 *status = doread (Line2, file, tflag);
  639.             }
  640.         break;
  641.  
  642.     case WRITECOM:
  643.     case UCWRITECOM:
  644.         i++;
  645.         flag = NO;
  646.         fflag = NO;
  647.         junk = ckchar ('>', '+', lin, &i, &flag, &junk);
  648.         if (flag == NO)
  649.             junk = ckchar ('!', '!', lin, &i, &fflag, &junk);
  650.         junk = ckchar ('x', 'X', lin, &i, &tflag, &junk);
  651.         if (getfn (lin, i - 1, file) == OK)
  652.         {
  653.             defalt (1, Lastln);
  654.             *status = dowrit (Line1, Line2, file, flag, fflag, tflag);
  655.         }
  656.         break;
  657.  
  658.     case PRINT:
  659.     case UCPRINT:
  660.         if (lin[i + 1] == '\n')
  661.         {
  662.             defalt (1, Topln);
  663.             *status = doprnt (Line1, Line2);
  664.         }
  665.         break;
  666.  
  667.     case PAGECOM:
  668.         defalt (1, min (Lastln, Botrow - Toprow + Topln));
  669.         if (Line1 <= 0)
  670.             Errcode = EORANGE;
  671.         else if (lin[i + 1] == '\n')
  672.         {
  673.             Topln = Line2;
  674.             Curln = Line2;
  675.             First_affected = Line2;
  676.             *status = OK;
  677.         }
  678.         break;
  679.  
  680.     case NAMECOM:
  681.     case UCNAMECOM:
  682.         i++;
  683.         if (getkn (lin, &i, &kname, DEFAULTNAME) != ERR
  684.             && lin[i] == '\n')
  685.             uniquely_name (kname, status);
  686.         break;
  687.  
  688.     case MARKCOM:
  689.     case UCMARKCOM:
  690.         i++;
  691.         if (getkn (lin, &i, &kname, DEFAULTNAME) != ERR
  692.             && lin[i] == '\n')
  693.         {
  694.             defalt (Curln, Curln);
  695.             *status = domark (kname);
  696.         }
  697.         break;
  698.  
  699.     case '\n':
  700.         line3 = nextln (Curln);
  701.         defalt (line3, line3);
  702.         *status = doprnt (Line2, Line2);
  703.         break;
  704.  
  705.     case LOCATECMD:
  706.     case UCLOCATECMD:
  707.         if (lin[i+1] == '\n')
  708.         {
  709.             char *sysname ();
  710.  
  711.             remark (sysname ());
  712.             *status = OK;
  713.         }
  714.         break;
  715.  
  716.     case OPTCOM:
  717.     case UCOPTCOM:
  718.         if (Nlines == 0)
  719.             *status = doopt (lin, &i);
  720.         else
  721.             Errcode = EBADLNR;
  722.         break;
  723.  
  724.     case QUIT:
  725.     case UCQUIT:
  726.         i++;
  727.         if (Nlines != 0)
  728.             Errcode = EBADLNR;
  729.         else if (ckupd (lin, &i, QUIT, status) == OK)
  730.             if (lin[i] == '\n')
  731.                 *status = EOF;
  732.             else
  733.                 *status = ERR;
  734.         break;
  735.  
  736.     case HELP:
  737.     case UCHELP:
  738.         i++;
  739.         if (Nlines == 0)
  740.             dohelp (lin, &i, status);
  741.         else
  742.             Errcode = EBADLNR;
  743.         break;
  744.  
  745.     case MISCCOM:        /* miscellanious features */
  746.     case UCMISCCOM:
  747.         i++;
  748.         switch (lin[i]) {
  749.         case 'b':    /* draw box */
  750.         case 'B':
  751.             defalt (Curln, Curln);
  752.             i++;
  753.             *status = draw_box (lin, &i);
  754.             break;
  755.  
  756.         default:
  757.             Errcode = EWHATZAT;
  758.             break;
  759.         }
  760.         break;
  761.  
  762.     case SHELLCOM:
  763.         i++;
  764.         defalt (Curln, Curln);
  765.         *status = doshell (lin, &i);
  766.         break;
  767.  
  768.     default:
  769.         Errcode = EWHATZAT;    /* command not recognized */
  770.         break;
  771.     }
  772.  
  773.     if (*status == OK)
  774.         Probation = NO;
  775.  
  776.     return (*status);
  777. }
  778.  
  779.  
  780. /* dohelp --- display documentation about editor */
  781.  
  782. dohelp (lin, i, status)
  783. char lin[];
  784. int *i, *status;
  785. {
  786.     char filename[MAXLINE];
  787.     char swt_filename[MAXLINE];
  788.     static char helpdir[] = "/usr/local/lib/se_h";    /* help scripts */
  789.     int j;
  790.     FILE *fp, *fopen ();
  791.  
  792.     SKIPBL (lin, *i);
  793.     if (lin[*i] == NEWLINE)
  794.         sprintf (filename, "%s/elp", helpdir);
  795.     else
  796.     {
  797.         /* build filename from text after "h" */
  798.         sprintf (filename, "%s/%s", helpdir, &lin[*i]);
  799.         j = strlen (filename);
  800.         filename[j-1] = EOS;    /* lop off newline */
  801.     }
  802.  
  803.     /* map to lower case */
  804.     for (j = 0; filename[j] != EOS; j++)
  805.         if (isupper (filename[j]))
  806.             filename[j] = tolower (filename[j]);
  807.  
  808.     *status = OK;
  809.     if ((fp = fopen (filename, "r")) == NULL)
  810.     {
  811.         *status = ERR;
  812.         Errcode = ENOHELP;
  813.     }
  814.     else
  815.     {
  816. #ifdef u3b2
  817.         /* 3B2 seems to have problems with stdio and malloc... */
  818.         char buf[BUFSIZ];
  819.         setbuf (fp, buf);
  820. #endif
  821.  
  822.         /* status is OK */
  823.         display_message (fp);    /* display the help script */
  824.         fclose (fp);
  825.     }
  826. }
  827.  
  828.  
  829. /* doopt --- interpret option command */
  830.  
  831. int doopt (lin, i)
  832. char lin[];
  833. int *i;
  834. {
  835.     int temp, line, stat;
  836.     char tempstr[4];
  837.     int ret;
  838.     int dosopt ();
  839.     int ctoi ();
  840.  
  841.     (*i)++;
  842.     ret = ERR;
  843.  
  844.     switch (lin[*i]) {
  845.  
  846.     case 'g':        /* substitutes in a global can(not) fail */
  847.     case 'G':
  848.         if (lin[*i + 1] == '\n')
  849.         {
  850.             ret = OK;
  851.             Globals = ! Globals;    /* toggle */
  852.             if (Globals == YES)
  853.                 remark ("failed global substitutes continue");
  854.             else
  855.                 remark ("failed global substitutes stop");
  856.         }
  857.         break;
  858.  
  859.     case 'h':
  860.     case 'H':        /* do/don't use hardware insert/delete */
  861.         if (lin[*i + 1] == '\n')
  862.         {
  863.             ret = OK;
  864.             No_hardware = ! No_hardware;
  865.             if (No_hardware == YES)
  866.                 remark ("no line insert/delete");
  867.             else
  868.                 remark ("line insert/delete");
  869.         }
  870.         break;
  871.  
  872.     case 'k':        /* tell user if buffer saved or not */
  873.     case 'K':
  874.         if (lin[*i + 1] == '\n')
  875.         {
  876.             ret = OK;
  877.             if (Buffer_changed == YES)
  878.                 remark ("not saved");
  879.             else
  880.                 remark ("saved");
  881.         }
  882.         break;
  883.  
  884.  
  885.     case 'z':    /* suspend the editor process */
  886.     case 'Z':
  887.         if (lin[*i + 1] == '\n')
  888.         {
  889.             ret = OK;
  890. #ifdef BSD
  891.             if (Catching_stops)
  892.             {
  893.                 if (Buffer_changed == YES)
  894.                     fprintf (stderr, "WARNING: buffer not saved\r\n");
  895.                 kill (getpid(), SIGTSTP);
  896.                 /* stop_hdlr() will do all the work for us */
  897.             }
  898. #else
  899.             remark ("process suspension not available");
  900. #endif
  901.         }
  902.         break;
  903.  
  904.     case 't':    /* set or display tab stops for expanding tabs */
  905.     case 'T':
  906.         ++(*i);
  907.         if (lin[*i] == '\n')
  908.         {
  909.             remark (Tabstr);
  910.             ret = OK;
  911.         }
  912.         else
  913.         {
  914.             ret = settab (&lin[*i]);
  915.             if (ret == OK)
  916.                 strcpy (Tabstr, &lin[*i]);
  917.             else    /* defaults were set */
  918.                 strcpy (Tabstr, "+4");
  919.         }
  920.         break;
  921.  
  922.     case 'w':    /* set or display warning column */
  923.     case 'W':
  924.         ++(*i);
  925.         if (lin[*i] == '\n')
  926.             ret = OK;
  927.         else
  928.         {
  929.             temp = ctoi (lin, i);
  930.             if (lin[*i] == '\n')
  931.                 if (temp > 0 && temp < MAXLINE - 3)
  932.                 {
  933.                     ret = OK;
  934.                     Warncol = temp;
  935.                 }
  936.                 else
  937.                     Errcode = ENONSENSE;
  938.         }
  939.         if (ret == OK)
  940.             saynum (Warncol);
  941.         break;
  942.  
  943.     case '-':    /* fix window in place on screen, or erase it */
  944.         ++(*i);
  945.         if (getnum (lin, i, &line, &stat) == EOF)
  946.         {
  947.             mesg ("", HELP_MSG);
  948.             if (Toprow > 0)
  949.             {
  950.                 Topln = max (1, Topln - Toprow);
  951.                 Toprow = 0;
  952.                 First_affected = Topln;
  953.             }
  954.             ret = OK;
  955.         }
  956.         else if (stat != ERR && lin[*i] == '\n')
  957.             if (Toprow + (line - Topln + 1) < Cmdrow)
  958.             {
  959.                 Toprow += line - Topln + 1;
  960.                 Topln = line + 1;
  961.                 for (temp = 0; temp < Ncols; temp++)
  962.                     load ('-', Toprow - 1, temp);
  963.                 if (Topln > Lastln)
  964.                     adjust_window (1, Lastln);
  965.                 if (Curln < Topln)
  966.                     Curln = min (Topln, Lastln);
  967.                 ret = OK;
  968.             }
  969.             else
  970.                 Errcode = EORANGE;
  971.         break;
  972.  
  973.     case 'a':    /* toggle absolute line numbering */
  974.     case 'A':
  975.         if (lin[*i + 1] == '\n')
  976.         {
  977.             Absnos = ! Absnos;
  978.             ret = OK;
  979.         }
  980.         break;
  981.  
  982.     case 'c':    /* toggle case option */
  983.     case 'C':
  984.         if (lin[*i + 1] == '\n')
  985.         {
  986.             ret = OK;
  987.             Invert_case = ! Invert_case;
  988.             if (Rel_a == 'A')
  989.             {
  990.                 Rel_a = 'a';
  991.                 Rel_z = 'z';
  992.             }
  993.             else
  994.             {
  995.                 Rel_a = 'A';
  996.                 Rel_z = 'Z';
  997.             }
  998.         }
  999.  
  1000.         mesg (Invert_case ? "CASE" : "", CASE_MSG);
  1001.         break;
  1002.  
  1003.     case 'd':    /* set or display placement of "." after a delete */
  1004.     case 'D':
  1005.         if (lin[*i + 1] == '\n')
  1006.         {
  1007.             if (Ddir == FORWARD)
  1008.                 remark (">");
  1009.             else
  1010.                 remark ("<");
  1011.             ret = OK;
  1012.         }
  1013.         else if (lin[*i + 2] != '\n')
  1014.             Errcode = EODLSSGTR;
  1015.         else if (lin[*i + 1] == '>')
  1016.         {
  1017.             ret = OK;
  1018.             Ddir = FORWARD;
  1019.         }
  1020.         else if (lin[*i + 1] == '<')
  1021.         {
  1022.             ret = OK;
  1023.             Ddir = BACKWARD;
  1024.         }
  1025.         else
  1026.             Errcode = EODLSSGTR;
  1027.         break;
  1028.  
  1029.     case 'v':    /* set or display overlay column */
  1030.     case 'V':
  1031.         ++(*i);
  1032.         if (lin[*i] == '\n')
  1033.         {
  1034.             if (Overlay_col == 0)
  1035.                 remark ("$");
  1036.             else
  1037.                 saynum (Overlay_col);
  1038.             ret = OK;
  1039.         }
  1040.         else
  1041.         {
  1042.             if (lin[*i] == '$' && lin[*i + 1] == '\n')
  1043.             {
  1044.                 Overlay_col = 0;
  1045.                 ret = OK;
  1046.             }
  1047.             else
  1048.             {
  1049.                 temp = ctoi (lin, i);
  1050.                 if (lin[*i] == '\n')
  1051.                 {
  1052.                     Overlay_col = temp;
  1053.                     ret = OK;
  1054.                 }
  1055.                 else
  1056.                     Errcode = ENONSENSE;
  1057.             }
  1058.         }
  1059.         break;
  1060.  
  1061.     case 'u':    /* set or display character for unprintable chars */
  1062.     case 'U':
  1063.         if (lin[*i + 1] == '\n')
  1064.         {
  1065.             ret = OK;
  1066.             tempstr[0] = tempstr[2] = '"';
  1067.             tempstr[1] = Unprintable;
  1068.             tempstr[3] = EOS;
  1069.             remark (tempstr);
  1070.         }
  1071.         else if (lin[*i + 2] == '\n')
  1072.         {
  1073.             if (lin[*i + 1] < ' ' || lin[*i + 1] >= DEL)
  1074.                 Errcode = ENONSENSE;
  1075.             else 
  1076.             {
  1077.                 ret = OK;
  1078.                 if (Unprintable != lin[*i + 1])
  1079.                 {
  1080.                     Unprintable = lin[*i + 1];
  1081.                     First_affected = Topln;
  1082.                 }
  1083.             }
  1084.         }
  1085.         break;
  1086.  
  1087.     case 'l':    /* set or display line number display option */
  1088.     case 'L':
  1089.         if (lin[*i+1] == '\n')
  1090.         {
  1091.             Nchoise = EOS;
  1092.             ret = OK;
  1093.         }
  1094.         else if (lin[*i + 2] == '\n' && 
  1095.             (lin[*i + 1] == CURLINE || lin[*i + 1] == LASTLINE
  1096.             || lin[*i + 1] == TOPLINE))
  1097.         {
  1098.             Nchoise = lin[*i + 1];
  1099.             ret = OK;
  1100.         }
  1101.         else if (lin[*i + 1] == 'm' || lin[*i + 1] == 'M')
  1102.         {
  1103.             /* set or display the left margin */
  1104.             (*i)++;
  1105.             if (lin[*i + 1] == '\n')
  1106.             {
  1107.                 saynum (Firstcol + 1);
  1108.                 ret = OK;
  1109.             }
  1110.             else 
  1111.             {
  1112.                 (*i)++;
  1113.                 temp = ctoi (lin, i);
  1114.                 if (lin[*i] == '\n')
  1115.                     if (temp > 0 && temp < MAXLINE)
  1116.                     {
  1117.                         First_affected = Topln;
  1118.                         Firstcol = temp - 1;
  1119.                         ret = OK;
  1120.                     }
  1121.                     else
  1122.                         Errcode = ENONSENSE;
  1123.             }
  1124.         }
  1125.         break;
  1126.  
  1127.     case 'f':    /* fortran (ugh, yick, gross) options */
  1128.     case 'F':
  1129.         if (lin[*i + 1] == '\n')
  1130.             ret = dosopt ("f");
  1131.         break;
  1132.  
  1133.     case 's':    /* set source options */
  1134.     case 'S':
  1135.         ret = dosopt (&lin[*i + 1]);
  1136.         break;
  1137.  
  1138.     case 'i':    /* set or display indent option */
  1139.     case 'I':
  1140.         ++(*i);
  1141.         if (lin[*i] == '\n')
  1142.             ret = OK;
  1143.         else if ((lin[*i] == 'a' || lin[*i] == 'A') && lin[*i + 1] == '\n')
  1144.         {
  1145.             Indent = 0;
  1146.             ret = OK;
  1147.         }
  1148.         else
  1149.         {
  1150.             temp = ctoi (lin, i);
  1151.             if (lin[*i] == '\n')
  1152.                 if (temp > 0 && temp < MAXLINE - 3)
  1153.                 {
  1154.                     ret = OK;
  1155.                     Indent = temp;
  1156.                 }
  1157.                 else
  1158.                     Errcode = ENONSENSE;
  1159.         }
  1160.         if (ret == OK)
  1161.             if (Indent > 0)
  1162.                 saynum (Indent);
  1163.             else
  1164.                 remark ("auto");
  1165.         break;
  1166.  
  1167.     case 'm':    /* toggle mail notification */
  1168.     case 'M':
  1169.         if (lin[*i + 1] == '\n')
  1170.         {
  1171.             Notify = ! Notify;    /* toggle notification */
  1172.             remark (Notify ? "notify on" : "notify off");
  1173.             ret = OK;
  1174.         }
  1175.         break;
  1176.  
  1177.     case 'x':
  1178.     case 'X':    /* toggle tab compression */
  1179.         if (lin[*i + 1] == '\n')
  1180.         {
  1181.             ret = OK;
  1182.             Compress = ! Compress;
  1183.             mesg (Compress ? "XTABS" : "", COMPRESS_MSG);
  1184.         }
  1185.         break;
  1186.  
  1187.     case 'y':    /* encrypt files */
  1188.     case 'Y':
  1189.         if (lin[*i + 1] == '\n')
  1190.         {
  1191.         crypt_toggle:
  1192.             ret = OK;
  1193.             Crypting = ! Crypting;
  1194.             if (Crypting )
  1195.                 do {
  1196.                     getkey ();
  1197.                     if (Key[0] == EOS)
  1198.                         remark ("Empty keys are not allowed.\n");
  1199.                 } while (Key[0] == EOS);
  1200.             else
  1201.                 Key[0] = EOS;
  1202.         }
  1203.         else
  1204.         {
  1205.             register int j;
  1206.  
  1207.             ret = OK;
  1208.             (*i)++;        /* *i was the 'y' */
  1209.             while (isspace (lin[*i]) && lin[*i] != '\n')
  1210.                 (*i)++;
  1211.             if (lin[*i] != '\n' && lin[*i] != EOS)
  1212.             {
  1213.                 for (j = 0; lin[*i] != '\n' && lin[*i] != EOS;
  1214.                     j++, (*i)++)
  1215.                     Key[j] = lin[*i];
  1216.                 Key[j] = EOS;
  1217.                 Crypting = YES;
  1218.             }
  1219.             else
  1220.                 goto crypt_toggle;
  1221.         }
  1222.         mesg (Crypting ? "ENCRYPT" : "", CRYPT_MSG);
  1223.         break;
  1224.  
  1225.     default:
  1226.         Errcode = EOWHAT;
  1227.  
  1228.     }
  1229.  
  1230.     return (ret);
  1231. }
  1232.  
  1233.  
  1234. /* domark --- name lines line1 through line2 as kname */
  1235.  
  1236. int domark (kname)
  1237. char kname;
  1238. {
  1239.     int line;
  1240.     int ret;
  1241.     register LINEDESC *k;
  1242.     LINEDESC *getind ();
  1243.  
  1244.     if (Line1 <= 0)
  1245.     {
  1246.         Errcode = EORANGE;
  1247.         ret = ERR;
  1248.     }
  1249.     else
  1250.     {
  1251.         k = getind (Line1);
  1252.         for (line = Line1; line <= Line2; line++)
  1253.         {
  1254.             if (intrpt())
  1255.                 return (ERR);
  1256.             k -> Markname = kname;
  1257.             k = NEXTLINE(k);
  1258.         }
  1259.         ret = OK;
  1260.     }
  1261.     return (ret);
  1262. }
  1263.  
  1264.  
  1265. /* doprnt --- set curln, locate window */
  1266.  
  1267. int doprnt (from, to)
  1268. int from, to;
  1269. {
  1270.  
  1271.     if (from <= 0)
  1272.     {
  1273.         Errcode = EORANGE;
  1274.         return (ERR);
  1275.     }
  1276.  
  1277.     adjust_window (from, to);
  1278.     Curln = to;
  1279.     return (OK);
  1280. }
  1281.  
  1282.  
  1283. /* doread --- read "file" after "line" */
  1284.  
  1285. int doread (line, file, tflag)
  1286. int line;
  1287. char *file;
  1288. int tflag;
  1289. {
  1290.     register int count, len, i;
  1291.     int ret;
  1292.     int strlen ();
  1293.     FILE *fd;
  1294.     FILE *fopen (), *crypt_open ();
  1295.     char lin1[MAXLINE], lin2[MAXLINE];
  1296.     char *fgets ();
  1297.     register LINEDESC *ptr;
  1298.     LINEDESC *sp_inject ();
  1299.     LINEDESC *getind ();
  1300.     char *expand_env ();
  1301.  
  1302.     file = expand_env (file);    /* expand $HOME, etc. */
  1303.  
  1304.     if (Savfil[0] == EOS)
  1305.     {
  1306.         strcpy (Savfil, file);
  1307.         mesg (Savfil, FILE_MSG);
  1308.     }
  1309.  
  1310.     if (Crypting)
  1311.         fd = crypt_open (file, "r");
  1312.     else
  1313.         fd = fopen (file, "r");
  1314.  
  1315.     if (fd == NULL)
  1316.     {
  1317.         ret = ERR;
  1318.         Errcode = ECANTREAD;
  1319.     }
  1320.     else
  1321.     {
  1322.         First_affected = min (First_affected, line + 1);
  1323.         ptr = getind (line);
  1324.         ret = OK;
  1325. #ifndef OLD_SCRATCH
  1326.         Curln = line;
  1327. #endif
  1328.         remark ("reading");
  1329.         for (count = 0; fgets (lin1, MAXLINE, fd) != NULL; count++)
  1330.         {
  1331.             if (intrpt ())
  1332.             {
  1333.                 ret = ERR;
  1334.                 break;
  1335.             }
  1336.             if (Compress == NO && tflag == NO)
  1337.                 ptr = sp_inject (lin1, strlen (lin1), ptr);
  1338.             else
  1339.             {
  1340.                 len = 0;
  1341.                 for (i = 0; lin1[i] != EOS && len < MAXLINE - 1; i++)
  1342.                     if (lin1[i] != '\t')
  1343.                         lin2[len++] = lin1[i];
  1344.                     else
  1345.                         do
  1346.                             lin2[len++] = ' ';
  1347.                         while (len % 8 != 0 
  1348.                             && len < MAXLINE - 1);
  1349.                 lin2[len] = EOS;
  1350.                 if (len >= MAXLINE)
  1351.                 {
  1352.                     ret = ERR;
  1353.                     Errcode = ETRUNC;
  1354.                 }
  1355.                 ptr = sp_inject (lin2, len, ptr);
  1356.             }
  1357.             if (ptr == NOMORE)
  1358.             {
  1359.                 ret = ERR;
  1360.                 break;
  1361.             }
  1362.         }
  1363.         if (Crypting)
  1364.             crypt_close (fd);
  1365.         else
  1366.             fclose (fd);
  1367.         saynum (count);
  1368.         Curln = line + count;
  1369.         svins (line, count);
  1370.     }
  1371.  
  1372.     return (ret);
  1373. }
  1374.  
  1375.  
  1376. /* dosopt --- set source language-related options */
  1377.  
  1378. int dosopt (lin)
  1379. char lin[];
  1380. {
  1381.     char lang[8];
  1382.     int i;
  1383.     int strbsr ();
  1384.     static struct {
  1385.         char *txt;
  1386.         int val;
  1387.     } ltxt[] = {    
  1388.         "",     1,
  1389.         "as",   2,
  1390.         "c",    3,
  1391.         "d",    1,
  1392.         "data", 1,
  1393.         "f",    4,
  1394.         "h",    3,
  1395.         "n",    1,
  1396.         "nr",   1,
  1397.         "nroff",1,
  1398.         "p",    3,
  1399.         "r",    3,
  1400.         "s",    2,
  1401.     };
  1402.  
  1403.     i = 0;
  1404.     getwrd (lin, &i, lang, 8);
  1405.  
  1406.     strmap (lang, 'a');
  1407.  
  1408.     i = strbsr ((char *)ltxt, sizeof (ltxt), sizeof (ltxt[0]), lang);
  1409.     if (i == EOF)
  1410.     {
  1411.         Errcode = ENOLANG;
  1412.         return (ERR);
  1413.     }
  1414.  
  1415.     /*
  1416.      * these are all the same under Unix, so factor
  1417.      * them out of the switch.
  1418.      */
  1419.  
  1420.     Rel_a = 'A';
  1421.     Rel_z = 'Z';
  1422.     Invert_case = NO;
  1423.     Compress = NO;
  1424.  
  1425.     switch (ltxt[i].val) {
  1426.     case 1:
  1427.         Warncol = 74;
  1428.         strcpy (Tabstr, "+4");
  1429.         break;
  1430.  
  1431.     case 2:
  1432.         Warncol = 72;
  1433.         strcpy (Tabstr, "17+8");
  1434.         Compress = YES;        /* except this one */
  1435.         break;
  1436.  
  1437.     case 3:
  1438.         Warncol = 74;
  1439.         strcpy (Tabstr, "+8");
  1440.         break;
  1441.  
  1442.     case 4:
  1443.         Warncol = 72;
  1444.         strcpy (Tabstr, "7+3");
  1445.         break;
  1446.     }
  1447.  
  1448.     settab (Tabstr);
  1449.     mesg (Invert_case == YES ? "CASE" : "", CASE_MSG);
  1450.     mesg (Compress == YES ? "XTABS" : "", COMPRESS_MSG);
  1451.  
  1452.     return (OK);
  1453. }
  1454.  
  1455.  
  1456. /* dotlit --- transliterate characters */
  1457.  
  1458. int dotlit (sub, allbut)
  1459. char sub[];
  1460. int allbut;
  1461. {
  1462.     char new[MAXLINE];
  1463.     char kname;
  1464.     int collap, x, i, j, line, lastsub, status;
  1465.     int ret;
  1466.     LINEDESC *inx;
  1467.     LINEDESC *gettxt (), *getind ();
  1468.  
  1469.     ret = ERR;
  1470.     if (Line1 <= 0)
  1471.     {
  1472.         Errcode = EORANGE;
  1473.         return (ret);
  1474.     }
  1475.  
  1476.     if (First_affected > Line1)
  1477.         First_affected = Line1;
  1478.  
  1479.     lastsub = strlen (sub) - 1;
  1480.     if ((strlen (Tlpat)  - 1) > lastsub || allbut == YES)
  1481.         collap = YES;
  1482.     else
  1483.         collap = NO;
  1484.  
  1485.     for (line = Line1; line <= Line2; line++)
  1486.     {
  1487.         if (intrpt ())    /* check for interrupts */
  1488.             return (ERR);
  1489.  
  1490.         inx = gettxt (line);    /* get text of line into txt, return index */
  1491.         j = 0;
  1492.         for (i = 0; Txt[i] != EOS && Txt[i] != '\n'; i++)
  1493.         {
  1494.             x = xindex (Tlpat, Txt[i], allbut, lastsub);
  1495.             if (collap == YES && x >= lastsub && lastsub >= 0)    /* collapse */
  1496.             {
  1497.                 new[j] = sub[lastsub];
  1498.                 j++;
  1499.                 for (i++; Txt[i] != EOS && Txt[i] != '\n'; i++)
  1500.                 {
  1501.                     x = xindex (Tlpat, Txt[i], allbut, lastsub);
  1502.                     if (x < lastsub)
  1503.                         break;
  1504.                 }
  1505.             }
  1506.             if (Txt[i] == EOS || Txt[i] == '\n')
  1507.                 break;
  1508.             if (x >= 0 && lastsub >= 0)    /* transliterate */
  1509.             {
  1510.                 new[j] = sub[x];
  1511.                 j++;
  1512.             }
  1513.             else if (x < 0)        /* copy */
  1514.             {
  1515.                 new[j] = Txt[i];
  1516.                 j++;
  1517.             }
  1518.             /* else
  1519.                 delete */
  1520.         }
  1521.  
  1522.         if (Txt[i] == '\n')    /* add a newline, if necessary */
  1523.         {
  1524.             new[j] = '\n';
  1525.             j++;
  1526.         }
  1527.         new[j] = EOS;        /* add the EOS */
  1528.  
  1529.         kname = inx -> Markname;    /* save the markname */
  1530.         delete (line, line, &status);
  1531.         ret = inject (new);
  1532.         if (ret == ERR)
  1533.             break;
  1534.         inx = getind (Curln);
  1535.         inx -> Markname = kname;    /* set markname */
  1536.         ret = OK;
  1537.         Buffer_changed = YES;
  1538.     }
  1539.  
  1540.     return (ret);
  1541. }
  1542.  
  1543. /* doundo --- restore last set of lines deleted */
  1544.  
  1545. int doundo (dflg, status)
  1546. int dflg;
  1547. int *status;
  1548. {
  1549.     LINEDESC *l1, *l2, *k1, *k2;
  1550.     LINEDESC *getind ();
  1551.     int oldcnt;
  1552.     int nextln (), prevln ();
  1553.  
  1554.     *status = ERR;
  1555.     if (dflg == NO && Line1 <= 0)
  1556.         Errcode = EORANGE;
  1557.     else if (Limbo == NOMORE)
  1558.         Errcode = ENOLIMBO;
  1559.     else if (Line1 > Line2)
  1560.         Errcode = EBACKWARD;
  1561.     else if (Line2 > Lastln)
  1562.         Errcode = ELINE2;
  1563.     else
  1564.     {
  1565.         *status = OK;
  1566.         Curln = Line2;
  1567. #ifdef OLD_SCRATCH
  1568.         k1 = getind (Line2);
  1569.         k2 = getind (nextln (Line2));
  1570.         l1 = Limbo;
  1571.         l2 = l1 -> Prevline;
  1572.         relink (k1, l1, l2, k2);
  1573.         relink (l2, k2, k1, l1);
  1574. #else
  1575.         blkmove (Limbo - Buf, MAXBUF - 1, Line2);
  1576. #endif
  1577.         svins (Line2, Limcnt);
  1578.         oldcnt = Limcnt;
  1579.         Limcnt = 0;
  1580.         Limbo = NOMORE;
  1581.         Lastln += oldcnt;
  1582.         if (dflg == NO)
  1583.             delete (Line1, Line2, status);
  1584.         Curln += oldcnt;
  1585.         if (First_affected > Line1)
  1586.             First_affected = Line1;
  1587.     }
  1588.  
  1589.     return (*status);
  1590. }
  1591.  
  1592. /* dowrit --- write "from" through "to" into file */
  1593.  
  1594. int dowrit (from, to, file, aflag, fflag, tflag)
  1595. int from, to, aflag, fflag, tflag;
  1596. char *file;
  1597. {
  1598.     FILE *fd;
  1599.     FILE *fopen (), *crypt_open ();
  1600.     register int line, ret, i, j;
  1601.     int strcmp (), access ();
  1602.     char tabs[MAXLINE];
  1603.     register LINEDESC *k;
  1604.     LINEDESC *getind ();
  1605.     char *expand_env ();
  1606.  
  1607.     ret = ERR;
  1608.     if (from <= 0)
  1609.         Errcode = EORANGE;
  1610.  
  1611.     else
  1612.     {
  1613.         file = expand_env (file);    /* expand $HOME, etc. */
  1614.  
  1615.         if (aflag == YES)
  1616.         {
  1617.             if (Crypting)
  1618.                 fd = crypt_open (file, "a");
  1619.             else
  1620.                 fd = fopen (file, "a");
  1621.         }
  1622.         else if (strcmp (file, Savfil) == 0 || fflag == YES
  1623.             || Probation == WRITECOM || access (file, 0) == -1)
  1624.         {
  1625.             if (Crypting)
  1626.                 fd = crypt_open (file, "w");
  1627.             else
  1628.                 fd = fopen (file, "w");
  1629.         }
  1630.         else
  1631.         {
  1632.             Errcode = EFEXISTS;
  1633.             Probation = WRITECOM;
  1634.             return (ret);
  1635.         }
  1636.         if (fd == NULL)
  1637.             Errcode = ECANTWRITE;
  1638.         else
  1639.         {
  1640.             ret = OK;
  1641.             remark ("writing");
  1642.             k = getind (from);
  1643.             for (line = from; line <= to; line++)
  1644.             {
  1645.                 if (intrpt ())
  1646.                     return (ERR);
  1647.                 gtxt (k);
  1648.                 if (Compress == NO && tflag == NO)
  1649.                     fputs (Txt, fd);
  1650.                 else
  1651.                 {
  1652.                     for (i = 0; Txt[i] == ' '; i++)
  1653.                         ;
  1654.                     for (j = 0; j < i / 8; j++)
  1655.                         tabs[j] = '\t';
  1656.                     tabs[j] = EOS;
  1657.                     fputs (tabs, fd);
  1658.                     fputs (&Txt[j * 8], fd);
  1659.                 }
  1660.                 k = NEXTLINE(k);
  1661.             }
  1662.             if (Crypting)
  1663.                 crypt_close (fd);
  1664.             else
  1665.                 fclose (fd);
  1666.             sync ();    /* just in case the system crashes */
  1667.             saynum (line - from);
  1668.             if (from == 1 && line - 1 == Lastln)
  1669.                 Buffer_changed = NO;
  1670.         }
  1671.     }
  1672.     return (ret);
  1673. }
  1674.  
  1675. /* expand_env --- expand environment variables in file names */
  1676.  
  1677. char *expand_env (file)
  1678. register char *file;
  1679. {
  1680.     register int i, j, k;        /* indices */
  1681.     char *getenv ();
  1682.     char var[MAXLINE];        /* variable name */
  1683.     char *val;            /* value of environment variable */
  1684.     static char buf[MAXLINE * 2];    /* expanded file name, static to not go away */
  1685.  
  1686.  
  1687.     i = j = k = 0;
  1688.     while (file[i] != EOS)
  1689.     {
  1690.         if (file[i] == ESCAPE)
  1691.         {
  1692.             if (file[i+1] == '$')
  1693.             {
  1694.                 buf[j++] = file[++i];    /* the actual $ */
  1695.                 i++;    /* for next time around the loop */
  1696.             }
  1697.             else
  1698.                 buf[j++] = file[i++];    /* the \ */
  1699.         }
  1700.         else if (file[i] != '$')    /* normal char */
  1701.             buf[j++] = file[i++];
  1702.         else            /* environment var */
  1703.         {
  1704.             i++;    /* skip $ */
  1705.             k = 0;
  1706.             while (file[i] != '/' && file[i] != EOS)
  1707.                 var[k++] = file[i++];    /* get var name */
  1708.             var[k] = EOS;
  1709.  
  1710.             if ((val = getenv (var)) != NULL)
  1711.                 for (k = 0; val[k] != EOS; k++)
  1712.                     buf[j++] = val[k];
  1713.                     /* copy val into file name */
  1714.             else if (file[i] == '/')
  1715.                 i++;    /* var not in enviroment; strip */
  1716.                     /* extra slash */
  1717.         }
  1718.     }
  1719.     buf[j] = EOS;
  1720.  
  1721.     return (buf);
  1722. }
  1723.  
  1724. /* crypt_open -- run files through crypt */
  1725.  
  1726. FILE *crypt_open (file, mode)
  1727. char *file, *mode;
  1728. {
  1729.     char buf[MAXLINE];
  1730.     FILE *fp, *popen ();
  1731.  
  1732.     if (! Crypting)
  1733.         return (NULL);
  1734.  
  1735.     while (Key[0] == EOS)
  1736.     {
  1737.         getkey ();
  1738.         if (Key[0] == EOS)
  1739.             fprintf (stderr, "The key must be non-empty!\r\n");
  1740.     }
  1741.  
  1742.     switch (mode[0]) {
  1743.     case 'r':
  1744.         sprintf (buf, "crypt %s < %s", Key, file);
  1745.         fp = popen (buf, "r");
  1746.         return (fp);        /* caller checks for NULL or not */
  1747.         break;
  1748.  
  1749.     case 'w':
  1750.         sprintf (buf, "crypt %s > %s", Key, file);
  1751.         fp = popen (buf, "w");
  1752.         return (fp);        /* caller checks for NULL or not */
  1753.         break;
  1754.  
  1755.     case 'a':
  1756.         sprintf (buf, "crypt %s >> %s", Key, file);
  1757.         fp = popen (buf, "w");
  1758.         return (fp);        /* caller checks for NULL or not */
  1759.         break;
  1760.     
  1761.     default:
  1762.         return (NULL);
  1763.     }
  1764. }
  1765.  
  1766. crypt_close (fp)
  1767. FILE *fp;
  1768. {
  1769.     pclose (fp);
  1770. }
  1771.  
  1772. /* getkey -- get an encryption key from the user */
  1773.  
  1774. #define repeat        do
  1775. #define until(cond)    while(!(cond))
  1776.  
  1777. getkey ()
  1778. {
  1779.     char *getpass ();    /* get input w/out echoing on screen */
  1780.  
  1781.     clrscreen ();        /* does NOT wipe out Screen_image */
  1782.     tflush ();
  1783.  
  1784.     ttynormal ();
  1785.  
  1786.     repeat
  1787.     {
  1788.         strcpy (Key, getpass ("Enter encryption key: "));
  1789.         if (strcmp (Key, getpass ("Again: ")) != 0)
  1790.         {
  1791.             Key[0] = EOS;
  1792.             fprintf (stderr, "didn't work. try again.\n");
  1793.         }
  1794.         /* else
  1795.             all ok */
  1796.     } until (Key[0] != EOS);
  1797.  
  1798.     ttyedit ();
  1799.  
  1800.     restore_screen ();
  1801. }
  1802. SHAR_EOF
  1803. fi # end of overwriting check
  1804. echo shar: extracting "'docmd2.c'" '(18109 characters)'
  1805. if test -f 'docmd2.c'
  1806. then
  1807.     echo shar: will not over-write existing file "'docmd2.c'"
  1808. else
  1809. cat << \SHAR_EOF > 'docmd2.c'
  1810. #ifndef lint
  1811. static char RCSid[] = "$Header: docmd2.c,v 1.3 86/07/17 17:20:29 arnold Exp $";
  1812. #endif
  1813.  
  1814. /*
  1815.  * $Log:    docmd2.c,v $
  1816.  * Revision 1.3  86/07/17  17:20:29  arnold
  1817.  * Some general code cleaning up.
  1818.  * 
  1819.  * Revision 1.2  86/07/11  15:11:04  osadr
  1820.  * Removed Georgia Tech specific code.
  1821.  * 
  1822.  * Revision 1.1  86/05/06  13:36:57  osadr
  1823.  * Initial revision
  1824.  * 
  1825.  * 
  1826.  */
  1827.  
  1828. /*
  1829. ** docmd2.c
  1830. **
  1831. ** routines to actually execute commands
  1832. */
  1833.  
  1834. #include "se.h"
  1835. #include "extern.h"
  1836.  
  1837.  
  1838. /* append --- append lines after "line" */
  1839.  
  1840. append (line, str)
  1841. int line;
  1842. char str[];
  1843. {
  1844.     char lin[MAXLINE];
  1845.     char term;
  1846.     int ret;
  1847.     int len, i, dpos, dotseen;
  1848.     int inject ();
  1849.  
  1850.     Curln = line;
  1851.  
  1852.     if (str[0] == ':')    /* text to be added is in the command line */
  1853.         ret = inject (&str[1]);
  1854.     else
  1855.     {
  1856.         Cmdrow = Toprow + (Curln - Topln) + 1;  /* 1 below Curln */
  1857.         lin[0] = EOS;
  1858.         if (Indent > 0 || line <= 0)
  1859.             len = max (0, Indent - 1);
  1860.         else /* do auto indent */
  1861.         {
  1862.             LINEDESC *k, *gettxt ();
  1863.             k = gettxt (line);
  1864.             for (len = 0; Txt[len] == ' '; len++)
  1865.                 ;
  1866.         }
  1867.         dpos = len;     /* position for terminating '.' */
  1868.  
  1869.         for (ret = NOSTATUS; ret == NOSTATUS; )
  1870.         {
  1871.             if (! hwinsdel())   /* do it the old, slow way */
  1872.             {
  1873.                 if (Cmdrow > Botrow)
  1874.                 {
  1875.                     Cmdrow = Toprow + 1;
  1876.                     cprow (Botrow, Toprow);
  1877.                     adjust_window (Curln, Curln);
  1878.                     if (First_affected > Topln)
  1879.                         First_affected = Topln;
  1880.                 }
  1881.                 clrrow (Cmdrow);
  1882.                 if (Cmdrow < Botrow)
  1883.                     clrrow (Cmdrow + 1);
  1884.             }
  1885.             else    /* try to be smart about it */
  1886.             {
  1887.                 if (Cmdrow > Botrow)
  1888.                 {
  1889.                     Cmdrow--;
  1890.                     dellines (Toprow, 1);
  1891.                     inslines (Cmdrow, 1);
  1892.                     Topln++;
  1893.                 }
  1894.                 else
  1895.                 {
  1896.                     dellines (Botrow, 1);
  1897.                     inslines (Cmdrow, 1);
  1898.                 }
  1899.             }
  1900.             prompt ("apd>");
  1901.             do
  1902.                 getcmd (lin, Firstcol, &len, &term);
  1903.             while (term == CURSOR_UP || term == CURSOR_DOWN
  1904.                 || term == CURSOR_SAME);
  1905.  
  1906.             dotseen = 0;
  1907.             if (lin[0] == '.' && lin[1] == '\n' && lin[2] == EOS)
  1908.                 dotseen = 1;
  1909.             for (i = 0; i < dpos && lin[i] == ' '; i++)
  1910.                 ;
  1911.             if (i == dpos && lin[dpos] == '.' && lin[dpos + 1] == '\n'
  1912.                 && lin[dpos+2] == EOS)
  1913.                 dotseen = 1;
  1914.  
  1915.             if (dotseen)
  1916.             {
  1917.                 if (hwinsdel())
  1918.                 {
  1919.                     dellines (Cmdrow, 1);
  1920.                     inslines (Botrow, 1);
  1921.                 }
  1922.                 ret = OK;
  1923.             }
  1924.             else if (inject (lin) == ERR)
  1925.                 ret = ERR;
  1926.             else            /* inject occured */
  1927.                 prompt ("");    /* erase prompt */
  1928.             Cmdrow++;
  1929.             if (term != FUNNY)
  1930.             {
  1931.                 if (Indent > 0)
  1932.                     len = Indent - 1;
  1933.                 else /* do auto indent */
  1934.                     for (len = 0; lin[len] == ' '; len++)
  1935.                         ;
  1936.                 dpos = len;
  1937.                 lin[0] = EOS;
  1938.             }
  1939.         }
  1940.         Cmdrow = Botrow + 1;
  1941.         if (hwinsdel())            /* since we take control */
  1942.         {                /* of the screen, we're sure */
  1943.             Sctop = Topln;        /* it's still OK */
  1944.  
  1945.             for (i = 0; i < Sclen; i++)
  1946.                 Scline[i] = Sctop + i <= Lastln ? i : -1;
  1947.         }
  1948.     }
  1949.     if (Curln == 0 && Lastln > 0)   /* for 0a or 1i followed by "." */
  1950.         Curln = 1;
  1951.     if (First_affected > line)
  1952.         First_affected = line;
  1953.  
  1954.     tflush ();
  1955.     return (ret);
  1956. }
  1957.  
  1958. /* copy --- copy line1 through line2 after line3 */
  1959.  
  1960. int copy (line3)
  1961. int line3;
  1962. {
  1963.     register int i;
  1964.     int ret;
  1965.     register LINEDESC *ptr3, *after3, *k;
  1966.     LINEDESC *getind ();
  1967.  
  1968.     ret = ERR;
  1969.  
  1970. #ifdef OLD_SCRATCH
  1971.     ptr3 = getind (line3);
  1972.     after3 = ptr3 -> Nextline;
  1973. #endif
  1974.  
  1975.     if (Line1 <= 0)
  1976.         Errcode = EORANGE;
  1977.     else
  1978.     {
  1979.         ret = OK;
  1980.         Curln = line3;
  1981.         k = getind (Line1);
  1982.         for (i = Line1; i <= Line2; i++)
  1983.         {
  1984.             gtxt (k);
  1985.             if (inject (Txt) == ERR || intrpt ())
  1986.             {
  1987.                 ret = ERR;
  1988.                 break;
  1989.             }
  1990. #ifdef OLD_SCRATCH
  1991.             if (k == ptr3)        /* make sure we don't copy stuff */
  1992.                 k = after3;    /* that's already been copied */
  1993.             else
  1994.                 k = k -> Nextline;
  1995. #else
  1996.             if (Line1 < line3)
  1997.                 k++;
  1998.             else
  1999.                 k += 2;
  2000.             /*
  2001.              * inject calls blkmove, which will shift the
  2002.              * lines down one in the array, so we add two
  2003.              * instead of one to get to the next line.
  2004.              */
  2005. #endif
  2006.         }
  2007.         First_affected = min (First_affected, line3 + 1);
  2008.     }
  2009.     return (ret);
  2010. }
  2011.  
  2012.  
  2013. /* delete --- delete lines from through to */
  2014.  
  2015. int delete (from, to, status)
  2016. int from, to, *status;
  2017. {
  2018.     int nextln (), prevln ();
  2019.     LINEDESC *k1, *k2, *j1, *j2, *l1;
  2020.     LINEDESC *getind ();
  2021.  
  2022.     if (from <= 0)          /* can't delete line 0 */
  2023.     {
  2024.         *status = ERR;
  2025.         Errcode = EORANGE;
  2026.     }
  2027.     else
  2028.     {
  2029.         if (First_affected > from)
  2030.             First_affected = from;
  2031. #ifdef OLD_SCRATCH
  2032.         k1 = getind (prevln (from));
  2033.         j1 = k1 -> Nextline;
  2034.         j2 = getind (to);
  2035.         k2 = j2 -> Nextline;
  2036.         relink (k1, k2, k1, k2);        /* close chain around deletion */
  2037. #else
  2038.         blkmove (from, to, MAXBUF - 1);    /* stick at end of buffer */
  2039. #endif
  2040.  
  2041.         Lastln -= to - from + 1;        /* adjust number of last line */
  2042.         Curln = prevln (from);
  2043.  
  2044. #ifdef OLD_SCRATCH
  2045.         if (Limbo != NOMORE)            /* discard lines in limbo */
  2046.         {
  2047.             l1 = Limbo -> Prevline;
  2048.             Limbo -> Prevline = Free;
  2049.             Free = l1;
  2050.         }
  2051. #endif
  2052.  
  2053.         Lost_lines += Limcnt;
  2054.         Limcnt = to - from + 1;        /* number of lines "deleted" */
  2055.  
  2056. #ifdef OLD_SCRATCH
  2057.         Limbo = j1;     /* put what we just deleted in limbo */
  2058.         relink (j2, j1, j2, j1);        /* close the ring */
  2059. #else
  2060.         /* point at first deleted */
  2061.         Limbo = &Buf[MAXBUF - (to - from + 1)];
  2062. #endif
  2063.         *status = OK;
  2064.         svdel (from, to - from + 1);
  2065.         Buffer_changed = YES;
  2066.     }
  2067.  
  2068.     return (*status);
  2069. }
  2070.  
  2071.  
  2072. /* join --- join a group of lines into a single line */
  2073.  
  2074. int join (sub)
  2075. char sub[];
  2076. {
  2077.     char new[MAXLINE];
  2078.     register int l, line, sublen;
  2079.     int ret;
  2080.     int inject (), delete (), prevln (), strlen ();
  2081.     register LINEDESC *k;
  2082.     LINEDESC *getind ();
  2083.  
  2084.     ret = OK;
  2085.     if (Line1 <= 0)
  2086.     {
  2087.         Errcode = EORANGE;
  2088.         return (ERR);
  2089.     }
  2090.  
  2091.     sublen = strlen (sub) + 1;      /* length of separator & EOS */
  2092.     line = Line1;
  2093.     k = getind (line);
  2094.     gtxt (k);
  2095.     move_ (Txt, new, (int) k -> Lineleng);    /* move in first chunk */
  2096.     l = k -> Lineleng;
  2097.  
  2098.     for (line++; line <= Line2; line++)
  2099.     {
  2100.         if (intrpt ())
  2101.             return (ERR);
  2102.         if (new[l - 2] == '\n') /* zap the NEWLINE */
  2103.             l--;
  2104.         k = NEXTLINE(k);    /* get the next line */
  2105.         gtxt (k);
  2106.         if (l + sublen - 1 + k -> Lineleng - 1 > MAXLINE)    /* won't fit */
  2107.         {
  2108.             Errcode = E2LONG;
  2109.             return (ERR);
  2110.         }
  2111.         move_ (sub, &new[l - 1], sublen);    /* insert separator string */
  2112.         l += sublen - 1;
  2113.         move_ (Txt, &new[l - 1], (int) k -> Lineleng);    /* move next line */
  2114.         l += k -> Lineleng - 1;
  2115.     }
  2116.     Curln = Line2;          /* all this will replace line1 through line2 */
  2117.     ret = inject (new);    /* inject the new line */
  2118.     if (ret == OK)
  2119.         ret = delete (Line1, Line2, &ret);    /* delete old lines */
  2120.     Curln++;
  2121.  
  2122.     if (First_affected > Curln)
  2123.         First_affected = Curln;
  2124.  
  2125.     return (ret);
  2126. }
  2127.  
  2128.  
  2129. /* move --- move line1 through line2 after line3 */
  2130.  
  2131. int move (line3)
  2132. int line3;
  2133. {
  2134.     int nextln (), prevln ();
  2135.     LINEDESC *k0, *k1, *k2, *k3, *k4, *k5;
  2136.     LINEDESC *getind ();
  2137.  
  2138.     if (Line1 <= 0)
  2139.     {
  2140.         Errcode = EORANGE;
  2141.         return (ERR);
  2142.     }
  2143.  
  2144.     if (Line1 <= line3 && line3 <= Line2)
  2145.     {
  2146.         Errcode = EINSIDEOUT;
  2147.         return (ERR);
  2148.     }
  2149.  
  2150. #ifdef OLD_SCRATCH
  2151.     k0 = getind (prevln (Line1));
  2152.     k1 = k0 -> Nextline;
  2153.     k2 = getind (Line2);
  2154.     k3 = k2 -> Nextline;
  2155.     relink (k0, k3, k0, k3);
  2156. #else
  2157.     blkmove (Line1, Line2, line3);
  2158. #endif
  2159.  
  2160.     if (line3 > Line1)
  2161.     {
  2162.         Curln = line3;
  2163. #ifdef OLD_SCRATCH
  2164.         line3 -= Line2 - Line1 + 1;
  2165. #endif
  2166.     }
  2167.     else
  2168.         Curln = line3 + (Line2 - Line1 + 1);
  2169.  
  2170. #ifdef OLD_SCRATCH
  2171.     k4 = getind (line3);
  2172.     k5 = k4 -> Nextline;
  2173.     relink (k4, k1, k2, k5);
  2174.     relink (k2, k5, k4, k1);
  2175. #endif
  2176.  
  2177.     Buffer_changed = YES;
  2178.     First_affected = min (First_affected, min (Line1, line3));
  2179.  
  2180.     return (OK);
  2181. }
  2182.  
  2183. /* overlay --- let user edit lines directly */
  2184.  
  2185. overlay (status)
  2186. int *status;
  2187. {
  2188.     char savtxt[MAXLINE], term, kname;
  2189.     static char empty[] = "\n";
  2190.     int lng, vcol, lcurln, scurln;
  2191.     int inject (), nextln (), prevln (), strcmp ();
  2192.     LINEDESC *indx;
  2193.     LINEDESC *getind (), *gettxt ();
  2194.  
  2195.     *status = OK;
  2196.     if (Line1 == 0)
  2197.     {
  2198.         Curln = 0;
  2199.         *status = inject (empty);
  2200.         if (*status == ERR)
  2201.             return;
  2202.         First_affected = 1;
  2203.         Line1 = 1;
  2204.         Line2++;
  2205.     }
  2206.  
  2207.     for (lcurln = Line1; lcurln <= Line2; lcurln++)
  2208.     {
  2209.         Curln = lcurln;
  2210.         vcol = Overlay_col - 1;
  2211.         do {
  2212.             adjust_window (Curln, Curln);
  2213.             updscreen ();
  2214.             Cmdrow = Curln - Topln + Toprow;
  2215.             indx = gettxt (Curln);
  2216.             lng = indx -> Lineleng;
  2217.             if (Txt[lng - 2] == '\n')       /* clobber newline */
  2218.                 lng--;
  2219.             if (vcol < 0)
  2220.                 vcol = lng - 1;
  2221.             while (lng - 1 < vcol)
  2222.             {
  2223.                 Txt[lng - 1] = ' ';
  2224.                 lng++;
  2225.             }
  2226.             Txt[lng - 1] = '\n';
  2227.             Txt[lng] = EOS;
  2228.             move_ (Txt, savtxt, lng + 1);    /* make a copy of the line */
  2229.             getcmd (Txt, Firstcol, &vcol, &term);
  2230.             if (term == FUNNY)
  2231.             {
  2232.                 if (First_affected > Curln)
  2233.                     First_affected = Curln;
  2234.                 Cmdrow = Botrow + 1;
  2235.                 return;
  2236.             }
  2237.             if (strcmp (Txt, savtxt) != 0)  /* was line changed? */
  2238.             {
  2239.                 kname = indx -> Markname;
  2240.                 delete (Curln, Curln, status);
  2241.                 scurln = Curln;
  2242.                 if (*status == OK)
  2243.                     *status = inject (Txt);
  2244.                 if (*status == ERR)
  2245.                 {
  2246.                     Cmdrow = Botrow + 1;
  2247.                     return;
  2248.                 }
  2249.                 indx = getind (nextln (scurln));
  2250.                 indx -> Markname = kname;
  2251.             }
  2252.             else
  2253.             {           /* in case end-of-line is moved */
  2254.                 if (First_affected > Curln)
  2255.                     First_affected = Curln;
  2256.             }
  2257.             switch (term) {
  2258.             case CURSOR_UP:
  2259.                 if (Curln > 1)
  2260.                     Curln--;
  2261.                 else
  2262.                     Curln = Lastln;
  2263.                 break;
  2264.             case CURSOR_DOWN:
  2265.                 if (Curln < Lastln)
  2266.                     Curln++;
  2267.                 else
  2268.                     Curln = min (1, Lastln);
  2269.                 break;
  2270.             case CURSOR_SAME:
  2271.                 vcol = 0;
  2272.                 break;
  2273.             }
  2274.         } while (term == CURSOR_UP || 
  2275.             term == CURSOR_DOWN ||
  2276.             term == CURSOR_SAME);
  2277.     }
  2278.     Cmdrow = Botrow + 1;
  2279.     return;
  2280. }
  2281.  
  2282.  
  2283. /* subst --- substitute "sub" for occurrences of pattern */
  2284.  
  2285. int subst (sub, gflag, glob)
  2286. char sub[];
  2287. int gflag, glob;
  2288. {
  2289.     char new[MAXLINE], kname;
  2290.     register int line, m, k, lastm;
  2291.     int j, junk, status, subbed, ret;
  2292.     int tagbeg[10], tagend[10];
  2293.     int amatch (), addset (), inject ();
  2294.     register LINEDESC *inx;
  2295.     LINEDESC *gettxt (), *getind ();
  2296.  
  2297.     if (Globals && glob)
  2298.         ret = OK;
  2299.     else
  2300.         ret = ERR;
  2301.  
  2302.     if (Line1 <= 0)
  2303.     {
  2304.         Errcode = EORANGE;
  2305.         return (ERR);
  2306.     }
  2307.  
  2308.     /* the following code has been removed for your protection
  2309.        index() occasionally grabs newlines out of the character class
  2310.        counter in a pattern.  for example [0-9] doesn't work due to this
  2311.  
  2312.         if (index (Pat, '\n') != -1)    # never delete NEWLINE
  2313.         {
  2314.             Errcode = EBADPAT;
  2315.             return (ERR);
  2316.         }
  2317.     */
  2318.  
  2319.     for (line = Line1; line <= Line2; line++)
  2320.     {
  2321.         if (intrpt ())
  2322.             break;
  2323.         j = 0;
  2324.         subbed = NO;
  2325.         inx = gettxt (line);
  2326.         lastm = -1;
  2327.         for (k = 0; Txt[k] != EOS; )
  2328.         {
  2329.             for (m = 1; m <= 9; m++)
  2330.             {
  2331.                 tagbeg[m] = -1;
  2332.                 tagend[m] = -1;
  2333.             }
  2334.             if (gflag == YES || subbed == NO)
  2335.                 m = amatch (Txt, k, Pat, &tagbeg[1], &tagend[1]);
  2336.             else
  2337.                 m = -1;
  2338.             if (m > -1 && lastm != m)       /* replace matched text */
  2339.             {
  2340.                 subbed = YES;
  2341.                 tagbeg[0] = k;
  2342.                 tagend[0] = m;
  2343.                 catsub (Txt, tagbeg, tagend, sub, new, &j, MAXLINE);
  2344.                 lastm = m;
  2345.             }
  2346.             if (m == -1 || m == k)  /* no match or null match */
  2347.             {
  2348.                 junk = addset (Txt[k], new, &j, MAXLINE);
  2349.                 k++;
  2350.             }
  2351.             else
  2352.                 k = m;    /* skip matched text */
  2353.         }
  2354.         if (subbed == YES)
  2355.         {
  2356.             if (addset (EOS, new, &j, MAXLINE) == NO)
  2357.             {
  2358.                 ret = ERR;
  2359.                 Errcode = E2LONG;
  2360.                 break;
  2361.             }
  2362.             kname = inx -> Markname;
  2363.             delete (line, line, &status);    /* remembers dot */
  2364.             ret = inject (new);
  2365.             if (First_affected > Curln)
  2366.                 First_affected = Curln;
  2367.             if (ret == ERR)
  2368.                 break;
  2369.             inx = getind (Curln);
  2370.             inx -> Markname = kname;
  2371.             ret = OK;
  2372.             Buffer_changed = YES;
  2373.         }
  2374.         else    /* subbed == NO */
  2375.             Errcode = ENOMATCH;
  2376.     }
  2377.  
  2378.     return (ret);
  2379. }
  2380.  
  2381.  
  2382. /* uniquely_name --- mark-name line; make sure no other line has same name */
  2383.  
  2384. uniquely_name (kname, status)
  2385. char kname;
  2386. int *status;
  2387. {
  2388.     register int line;
  2389.     register LINEDESC *k;
  2390.  
  2391.     defalt (Curln, Curln);
  2392.  
  2393.     if (Line1 <= 0)
  2394.     {
  2395.         *status = ERR;
  2396.         Errcode = EORANGE;
  2397.         return;
  2398.     }
  2399.  
  2400.     *status = OK;
  2401.     line = 0;
  2402.     k = Line0;
  2403.  
  2404.     do {
  2405.         line++;
  2406.         k = NEXTLINE(k);
  2407.         if (line == Line2)
  2408.             k -> Markname = kname;
  2409.         else if (k -> Markname == kname)
  2410.             k -> Markname = DEFAULTNAME;
  2411.     } while (line < Lastln);
  2412.  
  2413.     return;
  2414. }
  2415.  
  2416.  
  2417. /* draw_box --- draw or erase a box at coordinates in command line */
  2418.  
  2419. int draw_box (lin, i)
  2420. char lin[];
  2421. int *i;
  2422. {
  2423.     register int left, right, col, len;
  2424.     int junk;
  2425.     int ctoi (), strcmp (), inject (), delete ();
  2426.     register LINEDESC *k;
  2427.     LINEDESC *getind (), *gettxt ();
  2428.     char text[MAXLINE];
  2429.     char kname, ch;
  2430.  
  2431.     left = ctoi (lin, i);
  2432.     if (left <= 0 || left > MAXLINE)
  2433.     {
  2434.         Errcode = EBADCOL;
  2435.         return (ERR);
  2436.     }
  2437.  
  2438.     if (lin[*i] == ',')
  2439.     {
  2440.         (*i)++;
  2441.         SKIPBL (lin, *i);
  2442.         right = ctoi (lin, i);
  2443.         if (right <= 0 || right >= MAXLINE || left > right)
  2444.         {
  2445.             Errcode = EBADCOL;
  2446.             return (ERR);
  2447.         }
  2448.     }
  2449.     else
  2450.         right = left;
  2451.  
  2452.     SKIPBL (lin, *i);
  2453.     if (lin[*i] == '\n')
  2454.         ch = ' ';
  2455.     else
  2456.         ch = lin[(*i)++];
  2457.  
  2458.     if (lin[*i] != '\n')
  2459.     {
  2460.         Errcode = EEGARB;
  2461.         return (ERR);
  2462.     }
  2463.  
  2464.     if (Line1 <= 0)
  2465.     {
  2466.         Errcode = EORANGE;
  2467.         return (ERR);
  2468.     }
  2469.  
  2470.     for (Curln = Line1; Curln <= Line2; Curln++)
  2471.     {
  2472.         k = gettxt (Curln);
  2473.         len = k -> Lineleng;
  2474.         move_ (Txt, text, len);
  2475.  
  2476.         if (text[len - 2] == '\n')
  2477.             col = len - 1;
  2478.         else
  2479.             col = len;
  2480.         while (col <= right)
  2481.         {
  2482.             text[col - 1] = ' ';
  2483.             col++;
  2484.         }
  2485.         text[col - 1] = '\n';
  2486.         text[col] = EOS;
  2487.  
  2488.         if (Curln == Line1 || Curln == Line2)
  2489.             for (col = left; col <= right; col++)
  2490.                 text[col - 1] = ch;
  2491.         else
  2492.         {
  2493.             text[left - 1] = ch;
  2494.             text[right - 1] = ch;
  2495.         }
  2496.  
  2497.         if (strcmp (text, Txt) != 0)
  2498.         {
  2499.             kname = k -> Markname;
  2500.             if (delete (Curln, Curln, &junk) == ERR
  2501.                 || inject (text) == ERR)
  2502.                 return (ERR);
  2503.             k = getind (Curln);
  2504.             k -> Markname = kname;
  2505.             Buffer_changed = YES;
  2506.         }
  2507.     }
  2508.  
  2509.     Curln = Line1;        /* move to top of box */
  2510.     if (First_affected > Curln)
  2511.         First_affected = Curln;
  2512.     adjust_window (Curln, Curln);
  2513.     updscreen ();
  2514.  
  2515.     return (OK);
  2516. }
  2517.  
  2518.  
  2519. /* dfltsopt --- set the 's' option to the extension on the file name */
  2520.  
  2521. dfltsopt (name)
  2522. char name[];
  2523. {
  2524.     int i;
  2525.     int strlen (), dosopt ();
  2526.  
  2527.     for (i = strlen (name) - 1; i >= 0; i--)
  2528.         if (name[i] == '.')
  2529.         {
  2530.             dosopt (&name[i + 1]);
  2531.             break;
  2532.         }
  2533.     if (i < 0)
  2534.         dosopt ("");
  2535. }
  2536.  
  2537.  
  2538.  
  2539. /* doshell --- escape to the Shell to run one or more Unix commands */
  2540.  
  2541. /*
  2542. ** emulate vi: if running just a shell, redraw the screen as
  2543. ** soon as the shell exits. if running a program, let the user
  2544. ** redraw the screen when he/she is ready.
  2545. **
  2546. ** also emulate USG Unix 5.0 ed: a ! as the first character is
  2547. ** replaced by the previous shell command; an unescaped % is replaced
  2548. ** by the saved file name. The expanded command is echoed.
  2549. */
  2550.  
  2551. #ifdef BSD
  2552. #define DEFAULT_PATH    "/bin/csh"
  2553. #define DEF_SHELL    "csh"
  2554. #else
  2555. #define DEFAULT_PATH    "/bin/sh"
  2556. #define DEF_SHELL    "sh"
  2557. #endif
  2558.  
  2559. int doshell (lin, pi)
  2560. char lin[];
  2561. int *pi;
  2562. {
  2563.     int forkstatus, childstatus;
  2564.     int (*save_quit)(), (*save_int)();
  2565.     int int_hdlr ();
  2566.     int (*signal())();
  2567.     int i, auto_redraw;
  2568.     char *path, *name, *p, *getenv ();
  2569.     char new_command[MAXLINE];
  2570.     int j, k;
  2571.     static char sav_com[MAXLINE] = "";
  2572.     int expanded = NO;
  2573.  
  2574.     if (Nlines == 0)        /* use normal 'ed' behavior */
  2575.     {
  2576.         tflush ();    /* flush out the terminal output */
  2577.         position_cursor (Nrows - 1, 0);    /* bottom left corner */
  2578.  
  2579.         if ((p = getenv ("SHELL")) == NULL || strcmp (p, DEFAULT_PATH) == 0)
  2580.         {
  2581.             path = DEFAULT_PATH;
  2582.             name = DEF_SHELL;    /* default */
  2583.         }
  2584. #ifdef BSD
  2585.         /* on Berkeley systems, check the other shell */
  2586.         else if (strcmp (p, "/bin/sh") == 0)
  2587.         {
  2588.             path = "/bin/sh";
  2589.             name = "sh";
  2590.         }
  2591. #endif
  2592.         else
  2593.         {
  2594.             if (p[0] == '/')    /* full pathname there */
  2595.             {
  2596.                 /* work backwards to find just name */
  2597.                 path = p;
  2598.                 i = strlen (p);
  2599.                 while (p[i] != '/')
  2600.                     i--;
  2601.                 i++;        /* skip '/' */
  2602.                 name = &p[i];
  2603.             }
  2604.             else
  2605.             {
  2606.                 char buf[MAXLINE];
  2607.  
  2608.                 sprintf (buf, "unknown shell, using %s",
  2609.                     DEF_SHELL);
  2610.                 remark (buf);
  2611.                 path = DEFAULT_PATH;
  2612.                 name = DEF_SHELL;
  2613.             }
  2614.         }
  2615.  
  2616.         auto_redraw = (lin[*pi] == '\n') ? YES : NO;
  2617.  
  2618.         /* build command, checking for leading !, and % anywhere */
  2619.         if (lin[*pi] == '!')
  2620.         {
  2621.             if (sav_com[0] != EOS)
  2622.             {
  2623.                 for (j = 0; sav_com[j] != EOS; j++)
  2624.                     new_command[j] = sav_com[j];
  2625.                 if (new_command[j-1] == '\n')
  2626.                     j--;
  2627.                 (*pi)++;
  2628.                 expanded = YES;
  2629.             }
  2630.             else
  2631.             {
  2632.                 Errcode = ENOCMD;
  2633.                 return (ERR);
  2634.             }
  2635.         }
  2636.         else
  2637.             j = 0;
  2638.  
  2639.         for (i = *pi; lin[i] != EOS; i++)
  2640.         {
  2641.             if (lin[i] == ESCAPE)
  2642.             {
  2643.                 if (lin[i+1] != '%')
  2644.                 {
  2645.                     new_command[j++] = ESCAPE;
  2646.                     new_command[j++] = lin[++i];
  2647.                 }
  2648.                 else
  2649.                     new_command[j++] = lin[++i];
  2650.             }
  2651.             else if (lin[i] == '%')
  2652.             {
  2653.                 for (k = 0; Savfil[k] != EOS; k++)
  2654.                     new_command[j++] = Savfil[k];
  2655.                 expanded = YES;
  2656.             }
  2657.             else
  2658.                 new_command[j++] = lin[i];
  2659.         }
  2660.  
  2661.         if (new_command[j-1] == '\n')
  2662.             j--;
  2663.         new_command[j] = EOS;
  2664.  
  2665.         strcpy (sav_com, new_command);    /* save it */
  2666.  
  2667.         ttynormal ();
  2668. #ifndef HARD_TERMS
  2669.         t_exit ();
  2670. #endif
  2671.         write (1, "\n\n", 2);            /* clear out a line */
  2672.  
  2673.         forkstatus = fork();
  2674.         if (forkstatus == -1)   /* the fork failed */
  2675.         {
  2676.             ttyedit ();
  2677. #ifndef HARD_TERMS
  2678.             t_init ();
  2679. #endif
  2680.             Errcode = ECANTFORK;
  2681.             return ERR;
  2682.         }
  2683.  
  2684.         if (forkstatus == 0)    /* we're in the child process */
  2685.         {
  2686.             signal (SIGINT, SIG_DFL);
  2687.             signal (SIGQUIT, SIG_DFL);
  2688. #ifdef BSD
  2689.             if (strcmp (name, "sh") != 0)    /* not /bin/sh */
  2690.                 signal (SIGTSTP, SIG_DFL);
  2691.             else
  2692.                 signal (SIGTSTP, SIG_IGN);
  2693. #endif
  2694.             if (auto_redraw)    /* no params; run a shell */
  2695.             {
  2696.                 execl (path, name, 0);
  2697.                 _exit (RETERR);   /* exec failed, notify parent */
  2698.             }
  2699.             else
  2700.             {
  2701.                 if (expanded)        /* echo it */
  2702.                     printf ("%s\n", new_command);
  2703.  
  2704.                 execl (path, name, "-c", new_command, 0);
  2705.                 _exit (RETERR);
  2706.             }
  2707.         }
  2708.  
  2709.         /* we're in the parent process here */
  2710.         save_int = signal (SIGINT, SIG_IGN);        /* ignore interrupts */
  2711.         save_quit = signal (SIGQUIT, SIG_IGN);
  2712.         while (wait (&childstatus) != forkstatus)
  2713.             ;
  2714.         save_int = signal (SIGINT, save_int);       /* catch interupts */
  2715.         save_quit = signal (SIGQUIT, save_quit);
  2716.         write (1, "\n\n", 2);    /* clear out some message space */
  2717.         Currow = Nrows - 1;
  2718.         Curcol = 0;
  2719.         if ((childstatus >> 8) != 0)
  2720.         {
  2721.             ttyedit ();
  2722. #ifndef HARD_TERMS
  2723.             t_init ();
  2724. #endif
  2725.             Errcode = ENOSHELL;
  2726.             return ERR;
  2727.         }
  2728.  
  2729.         /* a la vi: */
  2730.         if (! auto_redraw)
  2731.         {
  2732.             int c;
  2733.  
  2734.             printf ("type return to continue: ");
  2735.             while ((c = getchar()) != '\n' && c != EOF)
  2736.                 ;
  2737.         }
  2738.  
  2739.         ttyedit ();
  2740. #ifndef HARD_TERMS
  2741.         t_init ();
  2742. #endif
  2743.         restore_screen ();
  2744.  
  2745.         return OK;
  2746.     }
  2747.  
  2748.     else
  2749.         remark ("Not implemented yet");
  2750.     
  2751.     return OK;
  2752. }
  2753. SHAR_EOF
  2754. fi # end of overwriting check
  2755. #    End of shell archive
  2756. exit 0
  2757.  
  2758.